﻿//=============================================================================
/**
	sprintf for AS3

	C の sprintf っぽいもの

		d
			+	符号を出力する
			-	桁指定時、左詰め
			0	余った桁を０で埋める

		f
				小数以下の桁指定のみ

		s
			-	左詰め
*/
//=============================================================================

package phpas3{
	public function sprintf(fmt:String, ...rest): String {
		var idx:int = 0;
		return fmt.replace(ReFmt,
			function(): String {
				var v:* = rest[idx];
				idx += 1;
				if (arguments[Keta] != "" || arguments[Denom] != "") {
					var flag:String = arguments[Flag];
					var b_zero:Boolean = arguments[Zero] != "";
					var keta:int = int(arguments[Keta]);

					switch (arguments[Post]) {
					case "d":
						return int2str(v, flag, b_zero, keta);
					case "x":
						return int2hexstr(v, HexTblS, flag, b_zero, keta);
					case "X":
						return int2hexstr(v, HexTblL, flag, b_zero, keta);
					case "f":
						return float2str(v, int(arguments[Denom]));
					case "s":
						return str2str(v, flag, keta);
					}
				}
				return v.toString();
			}
		);
	}
}


//-----------------------------------------------------------------------------
// file local definition

const ReFmt:RegExp = /%([+\-])?(0)?([1-9]\d*)?(?:\.(\d+)?)?([dxXfs])/g;
const Flag:int	= 1;
const Zero:int	= 2;
const Keta:int	= 3;
const Denom:int	= 4;
const Post:int	= 5;

const HexTblS:Array = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
const HexTblL:Array = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];


function str_x_n(s:String, n:int): String {
	var r:String = "";
	var t:String = s;
	for (; n > 0; n >>= 1) {
		if ((n & 1) != 0) {
			r = r.concat(t);
		}
		t = t.concat(t);
	}
	return r;
}


function int2str(v:int, flag:String, b_zero:Boolean, keta:int): String {
	var s:String = v.toString();
	if (keta == 0 || s.length >= keta) {
		return s;
	} else {
		if (flag == "-") {
			return s.concat(str_x_n(" ", keta - s.length));
		} else {
			if ((b_zero && v < 0) || (flag == "+" && v >= 0)) {
				var av:int;
				var f:String;
				if (v >= 0) {
					av = v;
					f = "+";
				} else {
					av = -v;
					f = "-";
				}
				return f.concat(str_x_n("0", keta - s.length - 1)).concat(av.toString());
			} else {
				if (flag == "+" && v >= 0) {
					s = "+".concat(s);
				}
				var c:String = b_zero ? "0" : " ";
				return str_x_n(c, keta - s.length).concat(s);
			}
		}
	}
}


function hexstr(v:int, n:int, tbl:Array): String {
	var s:String = "";
	for (; n > 0; n -= 1) {
		s = tbl[(v & 0x0f)].concat(s);
		v >>= 4;
		if (v == 0)	break;
	}
	return s;
}


function int2hexstr(v:int, tbl:Array, flag:String, b_zero:Boolean, keta:int): String {
	var s:String = hexstr(v, 8, tbl);
	if (keta == 0 || s.length >= keta) {
		return s;
	} else {
		if (flag == "-") {
			return s.concat(str_x_n(" ", keta - s.length));
		} else {
			var c:String = b_zero ? "0" : " ";
			return str_x_n(c, keta - s.length).concat(s);
		}
	}
}


function float2str(v:Number, keta:int): String {
	return v.toFixed(keta).toString();
}


function str2str(v:String, flag:String, keta:int): String {
	var len:int = v.length;
	if (keta <= 0 || len >= keta) {
		return v;
	} else {
		if (flag == "-") {
			return v.concat(str_x_n(" ", keta - len));
		} else {
			return str_x_n(" ", keta - len).concat(v);
		}
	}
}